<template>
  <n-spin :show="showSpin" size="small">
    <n-alert :title="prompt" :type="alertText[state].type">
    </n-alert>
    <template #description>
      计算中
    </template>
  </n-spin>
  <n-space vertical v-if="debug">
    <pre> {{ props }} </pre>
    <pre> {{ dps }} </pre>
  </n-space>
</template>

<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { computedAsync } from '@vueuse/core'
import { NSpin, NAlert } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { Maybe } from 'purify-ts/Maybe'
import { api } from '../utils'
import { Base64 } from 'js-base64'

// 传给该组件的参数，使用toRef取得响应式引用
// 值修改emit给上层组件
const props = defineProps({
  character: { type: Object, default: null },
  enemy: { type: Object, default: null },
  raidBuff: { type: Object, default: null },
  interval: { type: Number, default: 0.5 },
  dps: { type: Object, default: null },
  debug: { type: Boolean, default: false }
})

const emit = defineEmits(['update:dps'])

// local functions
// looks like lodash pick()?
const pick = (obj: any, keys: string[]): any => 
  keys.reduce((ret: any, k: string) => (ret[k] = obj[k], ret), {})
const propsHash = () => 
  Base64.encode(JSON.stringify(
    pick(props, ['character', 'enemy', 'raidBuff'])
  ), true)

// 绑定结果
const dpsResult = ref({})
watch(dpsResult, (_new, _old) => {
  emit('update:dps', _new)
})
// script setup上下文中不能使用Vue.$t，必须单独引入
const { t, locale } = useI18n() 

const alertText = {
  start: { type: 'info', text: '计算结果' },
  running: { type: 'warning', text: '计算中' },
  success: { type: 'success', text: '计算完成. !' },
  error: { type: 'error', text: '计算出错' }
}
const state = ref('start')
const prompt = computed(() => alertText[state.value].text.replace('!', `用时 ${(elapsed.value / 1000).toFixed(3)}s`))
const showSpin = computed(() => state == 'running')
const tick = ref(0)
const elapsed = ref(0)
const lastPropsHash = ref('')
const errorStop = ref(false)

const doCalculate = () => {
  const hash = propsHash()
  if (hash != lastPropsHash.value && props.character?.charId) {
    lastPropsHash.value = hash
    // 属性已经修改，重新计算
    state.value = 'running'
    const t = new Date().getTime()
    // adapt character to api args
    const char = { ...props.character }
    char.skillLevel--
    char.potentialRank--
    // copy args
    const args = {
      char,
      enemy: {...props.enemy},
      raidBuff: {...props.raidBuff}
    }
    console.log('dpsCalc update ->', args.char.charId)
    api.post(`dps/v1/`, { json: args }).json().then(result => {
      if (result.success) {
        dpsResult.value = result.value
        dpsResult.value.charName = char.name
        state.value = 'success'
        elapsed.value = new Date().getTime() - t
      } else {
        console.log('API error', result)
        state.value = 'error'
      }
    }, () => {
      console.log('Promise rejected')
      state.value = 'error'
    })
  }
}

// 定时计算
watch(tick, (_new, _old) => {
  doCalculate()
  // 安排下次定时
  if (!errorStop.value) {
    setTimeout(() => {
      ++tick.value
    }, props.interval * 1000)
  }
})
++tick.value
/*
// character刷新时计算
const charId = computed(() => props.character?.charId)
watch(charId, (_new, _old) => doCalculate())
*/
</script>

<style scoped>

</style>
